# boot_atat.s
# Use BIOS interruption to load head.s into 0x10000, and move to 0x0.
# Then enter protected mode, and jump to 0x0 to continue.
.code16

BOOTSEG = 0x07c0                # BIOS load boot code to 0000:0x7c00
SYSSEG  = 0x1000                # head.s is load to 0x10000, and moved to 0x0
SYSLEN  = 16                    # Max sector count that head.s needs

.global _start

.text

_start:
    ljmp    $BOOTSEG, $go       # Set cs from 0 to 0x07c0
go:
    mov     %cs, %ax
    mov     %ax, %ds
    mov     %ax, %ss
    movw    $0x400, %sp         # Set a temporary stack pointer, any value after the end of code is OK

load_system:                    # Use BIOS int 0x13, function 2 to read head code
    movw    $0x0000, %dx        # dh: header, dl: drive
    movw    $0x0002, %cx        # ch: sylinder, cl: sector, 1-based
    movw    $SYSSEG, %ax
    mov     %ax, %es
    xor     %bx, %bx            # es:bx: buffer address(0x1000:0x0000)
    movw    $0x200+SYSLEN, %ax  # ah: 02h, al: sectors to read
    int     $0x13
    jnc     ok_load             # CF is set on error, clear otherwise
die:  
    jmp     die

ok_load:                        # Move head from 0x10000 to 0x0, 8k maximum
    cli                         # Disable interrupts
    movw    $SYSSEG, %ax
    mov     %ax, %ds
    xor     %ax, %ax
    mov     %ax, %es
    movw    $0x1000, %cx        # Loop to move 4k times
    sub     %si, %si            # From ds:si = 0x1000:0
    sub     %di, %di            # To es:di = 0x0:0
    rep     movsw               # Move by word
    movw    $BOOTSEG, %ax
    mov     %ax, %ds
    lidt    idt_48              # Load IDTR
    lgdt    gdt_48              # Load GDTR
    movw    $0x0001, %ax        # Prepare to set PE(bit 0) of CR0 to enter protected mode
    lmsw    %ax                 # Set CR0(machine status word)
    ljmp    $8, $0              # cs has changed from a segment register to a segment selector
                                # Segment selector with value 8 points to the second segment descriptor in GDT

gdt:
    .word 0, 0, 0, 0            # Segment descriptor 0, not used
    .word 0x07ff                # Begin of segment descriptor 1, limit is 2047(8M)
    .word 0x0000                # Base address is 0x00000
    .word 0x9a00                # Code segment, execute/read
    .word 0x00C0                # Granularity is 4k
    .word 0x07FF                # Begin of segment descriptor 2, limit is 2047(8M)
    .word 0x0000                # Base address is 0x00000
    .word 0x9200                # Data segment, read/write
    .word 0x00c0                # Granularity is 4k
    
idt_48:
    .word 0                     # Limit of IDT
    .word 0, 0                  # Linear base address of IDT

gdt_48:
    .word 0x7ff                 # Limit of GDT
    .word 0x7c00+gdt, 0         # Linear base address of GDT

    .org 510
    .word 0xaa55                # Boot sector signature, for BIOS usage

